package cn.bnjy.service.impl;

import cn.bnjy.common.*;
import cn.bnjy.entity.*;
import cn.bnjy.mapper.MessageMapper;
import cn.bnjy.service.*;
import cn.bnjy.util.CollectionUtils;
import cn.bnjy.util.DateUtils;
import cn.bnjy.util.HttpUtils;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 描述：处理微信消息
 *
 * @since: 2018/11/10 14:21
 * @author: chavin
 */
@Service
@Slf4j
@Transactional
public class MessageServiceImpl implements IMessageService {

    @Autowired
    private MessageMapper messageMapper;

    @Autowired
    private IUserService userService;

    @Autowired
    private IAsyncService asyncService;

    @Autowired
    private IInviteService inviteService;

    @Autowired
    private IMenuService menuService;

    @Override
    public BaseMessage message(Map<String, String> params) {
        BaseMessage baseMessage;
        String msgType = params.get("MsgType");
        String fromUser = params.get("FromUserName");   // 发送方帐号（一个OpenID）
        String toUser = params.get("ToUserName");       // 开发者微信号
        if (MessageTypeConstant.TEXT.equals(msgType)) {
            baseMessage = reMsg(params);
        } else if (MessageTypeConstant.EVENT.equals(msgType)) {
            baseMessage = event(params);
        } else {
            baseMessage = new TextMessage("功能正在开发中，敬请期待...");
            baseMessage.setMsgType(MessageTypeConstant.TEXT);
        }
        if(baseMessage != null) {
            baseMessage.setCreateTime(System.currentTimeMillis());
            baseMessage.setFromUserName(toUser);
            baseMessage.setToUserName(fromUser);
        }
        return baseMessage;
    }

    /**
     * 从数据库获取对应的信息回复用户
     * @param params
     * @return
     */
    private BaseMessage reMsg(Map<String, String> params) {
        BaseMessage baseMessage;
        String msgType = params.get("MsgType");
        String content = params.get("Content");         // 用户发送的文本数据
        QueryWrapper<Message> queryWrapper = new QueryWrapper<>();
        if(MessageTypeConstant.EVENT.equals(msgType)) {
            queryWrapper.eq("re_type", "1");
        } else {
            // 先查出是否关键字，不是关键字则回复自动回复的消息
            queryWrapper.eq("re_type", "2").like("keyword", content);
        }
        Message message = messageMapper.selectOne(queryWrapper);
        if(message == null) {
            queryWrapper = new QueryWrapper<>();
            message = messageMapper.selectOne(queryWrapper.eq("re_type", "3"));
        }
        switch (message.getMsgType()) {
            case MessageTypeConstant.IMAGE:
                baseMessage = new ImageMessage(message.getMediaId());
                break;
            case MessageTypeConstant.VOICE:
                baseMessage = new VoiceMessage(message.getMediaId());
                break;
            case MessageTypeConstant.VIDEO:
                baseMessage = new VideoMessage(message.getMediaId(), message.getTitle(), message.getDescription());
                break;
            case MessageTypeConstant.MUSIC:
                baseMessage = new MusicMessage(message.getTitle(), message.getDescription(), message.getMusicUrl(), message.getHqMusicUrl(), message.getThumbMediaId());
                break;
            case MessageTypeConstant.NEWS:
                baseMessage = new NewsMessage("1", "", message.getTitle(), message.getDescription(), message.getPicUrl(), message.getUrl());
                baseMessage.setMsgType(MessageTypeConstant.NEWS);
                break;
            default:
                baseMessage = new TextMessage(message.getContent());
                break;
        }
        baseMessage.setMsgType(message.getMsgType());
        return baseMessage;
    }

    /**
     * 事件处理
     *
     * @param params
     * @return
     */
    private BaseMessage event(Map<String, String> params) {
        BaseMessage baseMessage = null;
        String event = params.get("Event");
        String openId = params.get("FromUserName");
        String eventKey = params.get("EventKey");       // 事件KEY值，qrscene_为前缀，后面为二维码的参数值
        switch (event.toLowerCase()) {
            case MessageTypeConstant.SUBSCRIBE:
                // 保存用户信息到数据库
                String userInfoStr = HttpUtils.get(WeiXinApi.USER_INFO.replace(WeiXinConstant.ACCESS_TOKEN, WeiXinAccessToken.getToken()).replace("OPENID", openId));
                UpdateWrapper<User> wrapper = new UpdateWrapper<>();
                User entity = toUser(userInfoStr);
                wrapper.eq("open_id", entity.getOpenId());
                userService.remove(wrapper);
                if(!userService.save(entity)) {
                    log.error("保存用户信息失败");
                } else {
                    log.info("用户信息已保存到数据库");
                }
                // 保存邀请关系
                saveInviteRelation(eventKey, openId, entity.getNickName());
                // 给用户发送关注后的消息
                baseMessage = reMsg(params);
                String activityStartTime = EasyData.CONFIG_MAP.get("ActivityStartTime");
                String activityEndTime = EasyData.CONFIG_MAP.get("ActivityEndTime");
                if(DateUtils.between(new Date(), activityStartTime, activityEndTime)) {
                    // 给用户再发送额外的消息
                    Map<String, String> data = Maps.newHashMap();
                    StringBuilder sb = new StringBuilder("欢迎！ ");
                    sb.append(entity.getNickName()).append(" 参加送书活动初级会计职称两本\n\n↓↓下方是您的专属海报，只需").append(Integer.parseInt(EasyData.CONFIG_MAP.get("ActivityStep1"))).append("位好友扫码助力后，即可免费领取实体书！【小技巧：转发到群和朋友圈很快就能完成】\n\n");
                    data.put("content", sb.toString());
                    asyncService.sendMore(entity.getOpenId(), MessageTypeConstant.TEXT, data);
                    // 异步发送海报
                    asyncService.sendQrcode(entity.getOpenId(), entity.getNickName());
                }
                break;
            case MessageTypeConstant.UNSUBSCRIBE:
                // 记录取消关注
                UpdateWrapper<User> updateWrapper = new UpdateWrapper<>();
                updateWrapper.eq("open_id", openId);
                User user = new User();
                user.setOpenId(openId);
                user.setSubscribe(0);
                if(!userService.update(user, updateWrapper)) {
                    log.error("用户取消关注入库失败");
                } else {
                    log.error("用户取消关注入库成功");
                }
                // 取消关注移除邀请关系，并发送消息给邀请者
                cancelInviteRelation(openId);
                break;
            case MessageTypeConstant.SCAN:
                break;
            case MessageTypeConstant.CLICK:
                // 查询关键字自动回复消息
                QueryWrapper<Menu> queryWrapper = new QueryWrapper<>();
                queryWrapper.eq("click_key", eventKey);
                Menu menu = menuService.getOne(queryWrapper);
                baseMessage = new TextMessage(menu.getMsg());
                baseMessage.setMsgType("text");
                break;
            default:
                break;
        }
        return baseMessage;
    }

    /**
     * 保存邀请关系
     * @param eventKey
     * @param openId
     */
    private void saveInviteRelation(String eventKey, String openId, String nickName) {
        if(StringUtils.isBlank(eventKey) || !eventKey.startsWith("qrscene_invite_")) {
            return;
        }
        String inviteOpenId = eventKey.substring("qrscene_invite_".length()); // scene_str_invite_openId
        QueryWrapper<Invite> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("invite_open_id", inviteOpenId).eq("new_comer_open_id", openId);
        if(inviteService.count(queryWrapper) <= 0) {
            inviteService.save(new Invite(inviteOpenId, openId));
            // 保存成功，给邀请人发送一条消息，说已经有多少个用户被邀请了
            sendTaskMsg(inviteOpenId, nickName);
        }
    }

    // 发送任务提醒给邀请者
    private void sendTaskMsg(String inviteOpenId, String nickName) {
        // 查询是否存在关系，并且时间是小于15号的
        String activityStartTime = EasyData.CONFIG_MAP.get("ActivityStartTime");
        String activityEndTime = EasyData.CONFIG_MAP.get("ActivityEndTime");
        if(DateUtils.between(new Date(), activityStartTime, activityEndTime)) {
            QueryWrapper<Invite> queryWrapper = new QueryWrapper<>();
            queryWrapper.eq("invite_open_id", inviteOpenId).groupBy("invite_open_id");
            int cnt = inviteService.count(queryWrapper);
            Map<String, String> data = Maps.newHashMap();
            String name = "";
            try {
                name = new String(nickName.getBytes(), "utf-8");
            } catch (UnsupportedEncodingException e) {
                log.error("微信名称转UTF-8失败：", e);
            }
            StringBuilder sb = new StringBuilder("您好！您的好友 ");
            sb.append(name).append(" 支持您了！！\n\n").append("您已获得").append(cnt).append("个好友的支持\n\n");
            int step1 = Integer.parseInt(EasyData.CONFIG_MAP.get("ActivityStep1"));
            int step2 = Integer.parseInt(EasyData.CONFIG_MAP.get("ActivityStep2"));
            int step3 = Integer.parseInt(EasyData.CONFIG_MAP.get("ActivityStep3"));
            String domain = EasyData.CONFIG_MAP.get("DOMAIN");
            if (cnt < step1) {
                sb.append("还差").append(step1 - cnt).append("个好友支持，即可获取第一阶段奖励，加油哦！！");
            } else if (cnt == step1) {
                sb.append("恭喜您获第一阶段任务奖励，").append("<a href='").append(domain).append("/activity/auth'>点击这里领取活动奖品</a>。\n\n继续邀请好友，完成第二阶段任务（").append(step2).append("人）还有优惠券送出哦！");
            } else if (cnt < step2) {
                sb.append("还差").append(step2 - cnt).append("个好友支持，即可获取第二阶段奖励，加油哦！！");
            } else if (cnt == step2) {
                sb.append("恭喜您获第二阶段任务奖励，").append("<a href='").append(domain).append("/activity/auth'>点击这里领取活动奖品</a>。\n\n继续邀请好友，完成第三阶段任务（").append(step3).append("人）还有免费直播课程可以学习哦！！");
            } else if(cnt < step3) {
                sb.append("还差").append(step3 - cnt).append("个好友支持，即可获取第三阶段奖励，加油哦！！");
            } else if(cnt == step3) {
                sb.append("恭喜您获第三阶段任务奖励，").append("<a href='\").append(domain).append(\"/activity/auth'>点击这里领取活动奖品</a>。感谢您的支持！更多精彩活动敬请关注！");
            } else {
                return;
            }
            data.put("content", sb.toString());
            asyncService.sendMore(inviteOpenId, MessageTypeConstant.TEXT, data);
            log.info("新用户关注，给邀请者发送消息：{}", data.get("content"));
        }
    }

    /**
     * 取消关注移除邀请关系，并发送消息给邀请者
     * @param openId
     */
    private void cancelInviteRelation(String openId){
        // 查询是否存在关系，并且时间是小于15号的
        String activityStartTime = EasyData.CONFIG_MAP.get("ActivityStartTime");
        String activityEndTime = EasyData.CONFIG_MAP.get("ActivityEndTime");
        if(DateUtils.between(new Date(), activityStartTime, activityEndTime)) {
            QueryWrapper<Invite> inviteWrapper = new QueryWrapper<>();
            inviteWrapper.eq("new_comer_open_id", openId);
            List<Invite> inviteList = inviteService.list(inviteWrapper);
            // 如果存在邀请关系，则删除，并且发送消息给邀请者
            if(CollectionUtils.isNotBlankList(inviteList) && inviteService.remove(inviteWrapper)) {
                inviteList.forEach(e -> {
                    String inviteOpenId = e.getInviteOpenId();
                    QueryWrapper<User> queryWrapper = new QueryWrapper<>();
                    queryWrapper.eq("open_id", openId);
                    User user = userService.getOne(queryWrapper);
                    QueryWrapper<Invite> wrapper = new QueryWrapper<>();
                    wrapper.eq("invite_open_id", inviteOpenId).groupBy("invite_open_id");
                    int cnt = inviteService.count(wrapper);
                    Map<String, String> data = Maps.newHashMap();
                    data.put("content", "您的好友" + user.getNickName() + "放弃为您助力！您的好友支持数为" + cnt);
                    asyncService.sendMore(inviteOpenId, MessageTypeConstant.TEXT, data);
                    log.info("取消关注，给邀请者发送消息：{}", data.get("content"));
                });
            }
        }
    }


    /**
     * 将json字符串转换为对象，因为微信里面的字段名与数据库中的不一致
     * @param jsonStr
     * @return
     */
    private User toUser(String jsonStr) {
        JSONObject jsonObj = JSON.parseObject(jsonStr);
        User user = new User();
        user.setOpenId(jsonObj.getString("openid"));
        user.setSubscribe(jsonObj.getIntValue("subscribe"));
        user.setNickName(jsonObj.getString("nickname"));
        user.setSex(jsonObj.getIntValue("sex"));
        user.setCity(jsonObj.getString("city"));
        user.setCountry(jsonObj.getString("country"));
        user.setProvince(jsonObj.getString("province"));
        user.setLanguage(jsonObj.getString("language"));
        user.setHeadImgUrl(jsonObj.getString("headimgurl"));
        user.setSubscribeTime(new Date(jsonObj.getLongValue("subscribe_time") * 1000));
        user.setUnionId(jsonObj.getString("unionid"));
        user.setRemark(jsonObj.getString("remark"));
        user.setGroupId(jsonObj.getString("groupid"));
        user.setTagidList(jsonObj.getString("tagid_list"));
        user.setSubscribeScene(jsonObj.getString("subscribe_scene"));
        user.setQrScene(jsonObj.getString("qr_scene"));
        user.setQrSceneStr(jsonObj.getString("qr_scene_str"));
        user.setCreateTime(new Date());
        return user;
    }

}
